package com.yida.wy.vote.outside.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import com.yida.common.core.constant.SecurityConstants;
import com.yida.common.core.domain.R;
import com.yida.common.core.exception.ServiceException;
import com.yida.common.core.utils.CheckRemoteServiceResultUtils;
import com.yida.common.core.utils.DateUtils;
import com.yida.common.core.utils.StringUtils;
import com.yida.common.security.utils.SecurityUtils;
import com.yida.system.api.RemoteSmsService;
import com.yida.system.api.domain.SysSms;
import com.yida.wy.common.domain.WyBaseHouse;
import com.yida.wy.common.domain.WyBaseOwner;
import com.yida.wy.common.enums.WyBusinessHouseStatus;
import com.yida.wy.common.utils.WyConvertUtil;
import com.yida.wy.vote.outside.domain.WyVoteBuild;
import com.yida.wy.vote.outside.domain.WyVoteHouse;
import com.yida.wy.vote.outside.domain.WyVoteProject;
import com.yida.wy.vote.outside.domain.WyVoteResult;
import com.yida.wy.vote.outside.domain.dto.*;
import com.yida.wy.vote.outside.domain.request.WyVoteOwnerProjectQueryRequest;
import com.yida.wy.vote.outside.domain.request.WyVoteProjectQueryRequest;
import com.yida.wy.vote.outside.domain.request.WyVoteProjectRequest;
import com.yida.wy.vote.outside.enums.*;
import com.yida.wy.vote.outside.mapper.WyVoteProjectMapper;
import com.yida.wy.vote.outside.mapper.WyVoteTemplateMapper;
import com.yida.wy.vote.outside.service.IWyVoteBuildService;
import com.yida.wy.vote.outside.service.IWyVoteHouseService;
import com.yida.wy.vote.outside.service.IWyVoteProjectService;
import com.yida.wy.vote.outside.service.IWyVoteResultService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 投票项目Service业务层处理
 *
 * @author lqq
 * @date 2023-03-13
 */
@Service
public class WyVoteProjectServiceImpl implements IWyVoteProjectService {

    @Resource
    private WyVoteProjectMapper voteProjectMapper;

    @Resource
    private WyVoteTemplateMapper voteTemplateMapper;

    @Resource
    private IWyVoteBuildService voteBuildService;

    @Resource
    private IWyVoteResultService voteResultService;

    @Resource
    private IWyVoteHouseService voteHouseService;

    @Resource
    private RemoteSmsService remoteSmsService;

    /**
     * 查询投票项目
     *
     * @param voteId 投票项目主键
     * @return 投票项目
     */
    @Override
    public WyVoteProject selectVoteProjectByVoteId(Long voteId) {
        return voteProjectMapper.selectVoteProjectByVoteId(voteId);
    }

    /**
     * 查询投票项目列表
     *
     * @param voteProject 投票项目
     * @return 投票项目
     */
    @Override
    public List<WyVoteProject> selectVoteProjectList(WyVoteProjectQueryRequest voteProject) {
        return voteProjectMapper.selectVoteProjectList(voteProject);
    }

    /**
     * 查询投票公示项目列表
     *
     * @param voteProject 投票项目
     * @return 投票项目
     */
    @Override
    public List<WyVoteProject> selectVotePublicizeProjectList(WyVoteProjectQueryRequest voteProject) {
        return voteProjectMapper.selectVotePublicizeProjectList(voteProject);
    }

    /**
     * 新增投票项目
     *
     * @param voteProject 投票项目
     * @return 结果
     */
    @Override
    public int insertVoteProject(WyVoteProject voteProject) {
        voteProject.setCreateUserId(SecurityUtils.getLoginUser().getSysOutsideUser().getUserId());
        voteProject.setCreateBy(SecurityUtils.getLoginUser().getSysOutsideUser().getRealName());
        voteProject.setCreateTime(DateUtils.getNowDate());
        return voteProjectMapper.insertVoteProject(voteProject);
    }

    /**
     * 修改投票项目
     *
     * @param voteProject 投票项目
     * @return 结果
     */
    @Override
    public int updateVoteProject(WyVoteProject voteProject) {
        voteProject.setUpdateBy(SecurityUtils.getLoginUser().getSysOutsideUser().getRealName());
        voteProject.setUpdateTime(DateUtils.getNowDate());
        return voteProjectMapper.updateVoteProject(voteProject);
    }

    /**
     * 修改投票项目访问次数
     *
     * @param voteProject 投票项目
     * @return 结果
     */
    @Override
    public int updateVoteProjectAccessNum(WyVoteProject voteProject) {
        return voteProjectMapper.updateVoteProjectAccessNum(voteProject);
    }

    /**
     * 批量删除投票项目
     *
     * @param voteIds 需要删除的投票项目主键
     * @return 结果
     */
    @Override
    public int deleteVoteProjectByVoteIds(Long[] voteIds) {
        return voteProjectMapper.deleteVoteProjectByVoteIds(voteIds);
    }

    /**
     * 删除投票项目信息
     *
     * @param voteId 投票项目主键
     * @return 结果
     */
    @Override
    public int deleteVoteProjectByVoteId(Long voteId) {
        return voteProjectMapper.deleteVoteProjectByVoteId(voteId);
    }

    /**
     * 投票详情
     *
     * @param voteId 投票ID
     * @return 结果
     */
    @Override
    public WyVoteProjectDetailDTO voteDetail(Long voteId) {
        //查询投票
        WyVoteProject project = selectVoteProjectByVoteId(voteId);
        if (StringUtils.isNull(project)) {
            throw new ServiceException("查无投票信息");
        }
        //查询已选楼栋
        List<WyVoteBuild> builds = voteBuildService.selectVoteBuildList(new WyVoteBuild() {{
            setCommunityId(project.getCommunityId());
            setVoteId(voteId);
        }});
        WyVoteProjectDetailDTO dto = BeanUtil.copyProperties(project, WyVoteProjectDetailDTO.class);
        if (StringUtils.isNotEmpty(builds)) {
            dto.setBuilds(BeanUtil.copyToList(builds, WyVoteBuildDTO.class));
        }
        return dto;
    }

    /**
     * 新增投票项目
     *
     * @param request 投票项目
     * @param data    基础楼栋房屋业主数据
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long addVote(WyVoteProjectRequest request, WyBaseBuildHouseOwnerDTO data) {
        //保存投票项目
        WyVoteProject project = BeanUtil.copyProperties(request, WyVoteProject.class);
        //投票状态
        project.setVoteStatus(WyVoteStatusEnum.NOT_VOTE.getCode());
        //审批状态
        project.setAuditStatus(WyVoteAuditStatusEnum.UNAUDITED.getCode());
        //发起端类型
        project.setInitiateType(WyVoteInitiateTypeEnum.E_VOTE.getCode());
        //提交状态
        project.setSubmitStatus(WyVoteSubmitStatusEnum.NOT_SUBMIT.getCode());
        //访问次数初始化
        project.setAccessNum(0);
        if (1 != insertVoteProject(project)) {
            throw new ServiceException("操作失败,保存投票失败");
        }
        //保存楼栋、房屋、业主
        data.setVoteId(project.getVoteId());
        if (!confirmSelectBuild(data)) {
            throw new ServiceException("操作失败,保存楼栋房屋业主数据失败");
        }
        return project.getVoteId();
    }

    /**
     * 编辑投票
     *
     * @param request 投票项目
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateOrSubmitVote(WyVoteProjectRequest request, boolean submitFlag) {
        //修改时投票信息是验证状态
        checkProjectForUpdate(request.getVoteId());
        //校验时间参数
        checkTime(request);
        //修改投票
        WyVoteProject project = BeanUtil.copyProperties(request, WyVoteProject.class);
        //如果是提交需修改状态
        if (submitFlag) {
            //提交状态
            project.setSubmitStatus(WyVoteSubmitStatusEnum.SUBMITTED.getCode());
            //未审核状态
            project.setAuditStatus(WyVoteAuditStatusEnum.UNAUDITED.getCode());
            //是否有创建选项
            if (StringUtils.isNull(voteTemplateMapper.selectVoteTemplateByVoteId(request.getVoteId()))){
                throw new ServiceException("操作失败,投票选项为空");
            }
        }
        if (1 != updateVoteProject(project)) {
            throw new ServiceException("操作失败,更新投票项目失败");
        }
        return Boolean.TRUE;
    }

    /**
     * 取消投票
     *
     * @param voteId 投票ID
     * @return 结果
     */
    @Override
    public int voteCancel(Long voteId) {
        if (StringUtils.isNull(selectVoteProjectByVoteId(voteId))) {
            throw new ServiceException("取消失败,查无投票信息");
        }
        WyVoteProject project = new WyVoteProject() {{
            setVoteId(voteId);
            setVoteStatus(WyVoteStatusEnum.CANCEL.getCode());
        }};
        return updateVoteProject(project);
    }

    /**
     * 短信通知
     *
     * @param voteId 投票ID
     * @return 结果
     */
    @Override
    public boolean voteSmsNotification(Long voteId) {
        WyVoteProject voteProject = selectVoteProjectByVoteId(voteId);
        if (StringUtils.isNull(voteProject)) {
            throw new ServiceException("通知失败,查无投票信息");
        }
        if (voteProject.getVoteStatus().equals(WyVoteStatusEnum.VOTE_ING.getCode()) && DateUtil.compare(DateUtils.getNowDate(), voteProject.getEndTime()) > 0) {
            throw new ServiceException("通知失败,投票已结束");
        }
        if (!voteProject.getVoteStatus().equals(WyVoteStatusEnum.VOTE_ING.getCode())) {
            throw new ServiceException("通知失败,投票未开始");
        }
        List<WyVoteResultDTO> owners = voteResultService.selectVoteResultList(new WyVoteResultDTO() {{
            setVoteId(voteId);
            setSelectFlag(WyBusinessHouseStatus.CONFIRM.getCode());
        }});
        //电话去重
        List<String> phones = owners.stream().map(o -> {
            String[] p = o.getOwnerPhone().split(",");
            String phone = null;
            for (String s : p) {
                phone = s;
            }
            return phone;
        }).distinct().collect(Collectors.toList());
        R<SysSms> r = remoteSmsService.sendSmsByPhonenumber(new SysSms() {{
            setSmsType(0);
            setPhonenumberList(phones);
            setSmsList(phones);
        }}, SecurityConstants.INNER);
        return !CheckRemoteServiceResultUtils.isCodeFail(r);
    }

    /**
     * 修改时投票信息是验证状态
     *
     * @param voteId 投票ID
     * @return /
     */
    @Override
    public WyVoteProject checkProjectForUpdate(Long voteId) {
        WyVoteProject voteProject = selectVoteProjectByVoteId(voteId);
        if (StringUtils.isNull(voteProject)) {
            throw new ServiceException("操作失败,查无投票信息");
        }
        if (!voteProject.getCreateUserId().equals(SecurityUtils.getLoginUser().getSysOutsideUser().getUserId())) {
            throw new ServiceException("操作失败,无权限操作");
        }
        if (voteProject.getVoteStatus().equals(WyVoteStatusEnum.CANCEL.getCode())) {
            throw new ServiceException("操作失败,投票已被取消");
        }
        if (voteProject.getVoteStatus().equals(WyVoteStatusEnum.VOTE_ING.getCode()) && DateUtil.compare(DateUtils.getNowDate(), voteProject.getEndTime()) > 0) {
            throw new ServiceException("操作失败,投票已结束");
        }
        if (voteProject.getVoteStatus().equals(WyVoteStatusEnum.VOTE_ING.getCode())) {
            throw new ServiceException("操作失败,投票正在进行中");
        }
        if (voteProject.getSubmitStatus().equals(WyVoteSubmitStatusEnum.SUBMITTED.getCode())) {
            throw new ServiceException("操作失败,投票已提交");
        }
        return voteProject;
    }

    /**
     * 发起投票
     *
     * @param voteId 投票ID
     * @return 结果
     */
    @Override
    public int voteStart(Long voteId) {
        WyVoteProject voteProject = selectVoteProjectByVoteId(voteId);
        if (StringUtils.isNull(voteProject)) {
            throw new ServiceException("发起投票失败,查无投票信息");
        }
        if (voteProject.getVoteStatus().equals(WyVoteStatusEnum.CANCEL.getCode())) {
            throw new ServiceException("发起投票失败,投票已被取消");
        }
        if (voteProject.getVoteStatus().equals(WyVoteStatusEnum.VOTE_ING.getCode()) && DateUtil.compare(DateUtils.getNowDate(), voteProject.getEndTime()) > 0) {
            throw new ServiceException("操作失败,投票已结束");
        }
        if (voteProject.getVoteStatus().equals(WyVoteStatusEnum.VOTE_ING.getCode())) {
            throw new ServiceException("发起投票失败,投票正在进行中");
        }
        if (!voteProject.getAuditStatus().equals(WyVoteAuditStatusEnum.AGREE.getCode())) {
            throw new ServiceException("发起投票失败,投票审核未通过");
        }
        if (DateUtil.compare(DateUtils.getNowDate(), voteProject.getStartTime()) < 0) {
            throw new ServiceException("发起投票失败,当前时间未到投票开始时间");
        }
        WyVoteProject project = new WyVoteProject() {{
            setVoteId(voteId);
            setVoteStatus(WyVoteStatusEnum.VOTE_ING.getCode());
        }};
        return updateVoteProject(project);
    }

    /**
     * 校验时间
     *
     * @param request 投票项目
     */
    @Override
    public void checkTime(WyVoteProjectRequest request) {
        if (DateUtil.compare(DateUtils.getNowDate(), request.getStartTime()) >= 0) {
            throw new ServiceException("选择的时间必须大于当前的时间");
        }
        if (DateUtil.compare(request.getStartTime(), request.getEndTime()) >= 0) {
            throw new ServiceException("投票结束时间必须大于投票发起时间");
        }
        if (DateUtil.compare(request.getEndTime(), request.getPublicEndTime()) >= 0) {
            throw new ServiceException("公示截止时间必须大于投票结束时间");
        }
    }


    /**
     * 选择楼栋
     *
     * @param baseAllDataDTO 基础楼栋房屋业主
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean confirmSelectBuild(WyBaseBuildHouseOwnerDTO baseAllDataDTO) {
        //插入楼栋
        List<WyVoteBuild> voteBuilds = BeanUtil.copyToList(baseAllDataDTO.getBaseBuilds(), WyVoteBuild.class);
        voteBuilds.forEach(vb -> {
            //验证是否已存在
            if (StringUtils.isNotEmpty(voteBuildService.selectVoteBuildList(new WyVoteBuild() {{
                setBuildId(vb.getBuildId());
                setVoteId(baseAllDataDTO.getVoteId());
            }}))) {
                throw new ServiceException("加入选择失败,楼栋已存在");
            }
            vb.setCreateBy(SecurityUtils.getLoginUser().getSysOutsideUser().getRealName());
            vb.setCreateTime(DateUtils.getNowDate());
            vb.setVoteId(baseAllDataDTO.getVoteId());
        });
        if (voteBuildService.insertBatchVoteBuild(voteBuilds) <= 0) {
            throw new ServiceException("加入选择失败,保存楼栋失败");
        }
        //插入房屋 分段插入
        List<List<WyBaseHouse>> houseList = WyConvertUtil.partition(baseAllDataDTO.getBaseHouses(), 100);
        houseList.forEach(l -> {
            List<WyVoteHouse> voteHouses = BeanUtil.copyToList(l, WyVoteHouse.class);
            voteHouses.forEach(vh -> {
                vh.setCreateBy(SecurityUtils.getLoginUser().getSysOutsideUser().getRealName());
                vh.setCreateTime(DateUtils.getNowDate());
                vh.setSelectFlag(WyBusinessHouseStatus.CONFIRM.getCode());
                vh.setVoteId(baseAllDataDTO.getVoteId());
            });
            if (voteHouseService.insertBatchVoteHouse(voteHouses) <= 0) {
                throw new ServiceException("加入选择失败,保存房屋失败");
            }
        });
        //插入业主（结果表） 分段插入
        List<List<WyBaseOwner>> ownerList = WyConvertUtil.partition(baseAllDataDTO.getBaseOwners(), 100);
        ownerList.forEach(l -> {
            List<WyVoteResult> voteResults = BeanUtil.copyToList(l, WyVoteResult.class);
            voteResults.forEach(vo -> {
                vo.setCreateBy(SecurityUtils.getLoginUser().getSysOutsideUser().getRealName());
                vo.setCreateTime(DateUtils.getNowDate());
                vo.setVoteType(WyOwnerVoteTypeEnum.NOT_VOTE.getCode());
                vo.setCommunityId(baseAllDataDTO.getCommunityId());
                vo.setVoteId(baseAllDataDTO.getVoteId());
            });
            if (voteResultService.insertBatchVoteResult(voteResults) <= 0) {
                throw new ServiceException("加入选择失败,保存业主失败");
            }
        });
        return Boolean.TRUE;
    }

    /**
     * 取消选择楼栋
     *
     * @param buildIds 投票楼栋ID集合
     * @param voteId   投票ID
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean cancelSelectBuild(Long[] buildIds, Long voteId) {
        List<Long> voteBuildIds = new ArrayList<Long>();
        //删除房屋、业主
        for (Long buildId : buildIds) {
            //查询楼栋标识码
            WyVoteBuild voteBuild = voteBuildService.selectVoteBuildByBuildIdAndVoteId(buildId, voteId);
            if (StringUtils.isNull(voteBuild)) {
                throw new ServiceException("取消失败,查无楼栋信息");
            }
            voteBuildIds.add(voteBuild.getVoteBuildId());
            //删除房屋
            List<WyVoteHouse> voteHouses = voteHouseService.selectVoteHouseList(new WyVoteHouse() {{
                setBuildCode(voteBuild.getBuildCode());
                setVoteId(voteId);
            }});
            if (StringUtils.isNotEmpty(voteHouses)) {
                Long[] voteHouseIds = voteHouses.stream().map(WyVoteHouse::getVoteHouseId).toArray(Long[]::new);
                voteHouseService.deleteVoteHouseByVoteHouseIds(voteHouseIds);
                //删除业主
                String[] houseCodes = voteHouses.stream().map(WyVoteHouse::getHouseCode).toArray(String[]::new);
                voteResultService.deleteVoteResultByHouseCodesAndVoteId(houseCodes, voteId);
            }
        }
        //删除楼栋
        if (StringUtils.isNotEmpty(voteBuildIds)) {
            if (0 == voteBuildService.deleteVoteBuildByVoteBuildIds(voteBuildIds.toArray(new Long[0]))) {
                throw new ServiceException("取消楼栋失败");
            }
        }
        return Boolean.TRUE;
    }

    /**
     * 选择房屋
     *
     * @param voteHouseIds 投票房屋ID集合
     * @param voteId       投票ID
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean confirmSelectHouse(Long[] voteHouseIds, Long voteId) {
        //修改时投票信息是验证状态
        checkProjectForUpdate(voteId);
        //修改房屋选择
        if (voteHouseService.updateBatchVoteHouseSelectFlag(voteHouseIds, WyBusinessHouseStatus.CONFIRM.getCode()) < 1) {
            throw new ServiceException("加入选择失败,更新房屋状态失败");
        }
        return Boolean.TRUE;
    }

    /**
     * 取消选择房屋
     *
     * @param voteHouseIds 投票房屋ID集合
     * @param voteId       投票ID
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean cancelSelectHouse(Long[] voteHouseIds, Long voteId) {
        //修改时投票信息是验证状态
        checkProjectForUpdate(voteId);
        //修改房屋选择
        if (voteHouseService.updateBatchVoteHouseSelectFlag(voteHouseIds, WyBusinessHouseStatus.CANCEL.getCode()) < 1) {
            throw new ServiceException("加入选择失败,更新房屋状态失败");
        }
        return Boolean.TRUE;
    }

    /**
     * 查询业主可投票项目列表
     *
     * @param request 业主ID
     * @return 投票项目集合
     */
    @Override
    public List<WyVoteOwnerProjectListDTO> selectVoteOwnerProjectList(WyVoteOwnerProjectQueryRequest request) {
        return voteProjectMapper.selectVoteOwnerProjectList(request);
    }
}


